﻿using System;
using System.Text;
using System.Data;
using System.Windows.Forms;
using MySql.Data.MySqlClient;
using HelpSystem;

namespace DAOLayer
{
    public class CDAOTransportions
    {
        private MySqlConnection m_Connection = null;
        private string m_user = null;

        /// <summary>
        /// Конструктор по умолчанию. Создаёт объект БД без подключения и данных.
        /// </summary>
        public CDAOTransportions()
        {
        }
        /// <summary>
        /// Конструктор, создаёт новый объект доступпа к данным базы данных
        /// </summary>
        /// <param name="ConnectionString">Строка подключения к СУБД.</param>
        public CDAOTransportions(string Server, string Database, string User, string Password)
        {
            ReconnectTo(Server, Database, User, Password);
            if (IsOpen)
                InitTables();
        }

        public void InitTables()
        {
            Transport = new AllTransport(this);
            TransportTypes = new AllTransportTypes(this);
        }

        /// <summary>
        /// Метод производящий переподключение к БД.
        /// </summary>
        /// <param name="Server">IP адрес или DNS имя сервера БД</param>
        /// <param name="Database">Имя базы данных</param>
        /// <param name="User">Имя пользователя для подключения</param>
        /// <param name="Password">Пароль пользователя</param>
        public void ReconnectTo(string Server, string Database, string User, string Password)
        {
            Close();
            string ConnectionString = "Database="+Database
                                    +";Data Source="+Server
                                    +";User Id="+User
                                    +";Password="+Password
                                    +";charset=utf8;";
            MySqlConnection NewConnection;
            try
            {
                NewConnection = new MySqlConnection(ConnectionString);
            }
            catch (MySqlException exc)
            {
                MessageBox.Show(exc.Message,
                                "Невозможно создать подключение к БД.",
                                MessageBoxButtons.OK,
                                MessageBoxIcon.Error);
                return;
            }
            NewConnection.StateChange += new StateChangeEventHandler(OnStateChange);
            m_Connection = NewConnection;
            Open();
        }
        /// <summary>
        /// Открыть текущее подключение к БД
        /// </summary>
        public bool Open()
        {
            try
            {
                if (Connection != null && Connection.State == ConnectionState.Closed)
                    Connection.Open();
            }
            catch (MySqlException exc)
            {
                switch ((MySqlErrorCode) exc.Number)
                {
                    case MySqlErrorCode.UnknownDatabase:
                    case MySqlErrorCode.UnableToConnectToHost:
                        {
                            Documentation.ShowError(Documentation.ErrorCode.UnableConnectToServer);
                        }
                        break;
                    case MySqlErrorCode.PasswordNoMatch:
                    case MySqlErrorCode.PasswordNotAllowed:
                    case MySqlErrorCode.AccessDenied:
                        {
                            Documentation.ShowError(Documentation.ErrorCode.AccessDenied);
                        }
                        break;
                    default:
                        {
                            Documentation.ShowError("MySQL Error " + exc.Number.ToString() + ":" + exc.InnerException.Message);
                        }
                        break;
                }
                return false;
            }
            return (Connection != null && Connection.State == ConnectionState.Open);
        }
        /// <summary>
        /// Возвращяет true, если подключение открыто, и false в противном случае.
        /// </summary>
        public bool IsOpen
        {
            get
            {
                return (Connection != null && Connection.State == ConnectionState.Open);
            }
        }
        /// <summary>
        /// Закрыть текущее подключение к БД
        /// </summary>
        public void Close()
        {
            if (m_Connection != null && m_Connection.State == ConnectionState.Open)
                m_Connection.Close();
        }
        /// <summary>
        /// Получить текущие параметры подключения к БД
        /// </summary>
        public MySqlConnection Connection
        {
            get
            {
                return m_Connection;
            }
        }
        /// <summary>
        /// Получить версию сервера БД
        /// </summary>
        public string ServerVersion
        {
            get
            {
                return m_Connection.ServerVersion;
            }
        }
        /// <summary>
        /// Имя пользователя, от имени которого осуществляется подключение к БД.
        /// </summary>
        public string User
        {
            get
            {
                if (m_user == null)
                    return "";
                else
                    return m_user;
            }
        }

        #region Транспорт
        /// <summary>
        /// Класс описывающий доступ к таблице транспорта
        /// </summary>
        public class AllTransport
        {
            //Адаптер таблицы 
            private MySqlDataAdapter Adapter = null;
            private CDAOTransportions DataBase = null;
            private Timer AutoUpdater = new Timer();
            /// <summary>
            /// Таблица содежащая все записи БД о транспорте 
            /// </summary>
            public DataTable Table = null;
            /// <summary>
            /// Инкапсулирует источник данных для формы. 
            /// </summary>
            public BindingSource TableBindingSource = null;
            /// <summary>
            /// Конструктор, создаёт новый объект транспорта содержащий данные таблицы транпорта, её 
            /// </summary>
            /// <param name="Transportions"></param>
            public AllTransport(CDAOTransportions Transportions)
            {
                if (Transportions == null)
                    Documentation.ShowError("Ошибка создания объекта транпорта. Переданный объект базы данных не существует.");
                DataBase = Transportions;
                
                //Создаём команды адаптера данных (SELECT, UPDATE, INSERT, UPDATE)
                //SELECT
                Adapter = new MySqlDataAdapter("SELECT transport_id, transport_type_id, gov_number, vin, date_to FROM transport;", DataBase.Connection);
                //UPDATE
                Adapter.UpdateCommand = new MySqlCommand("UPDATE transport SET transport_type_id=@TransportTypeID, gov_number=@GovNumber, vin=@VIN, date_TO=@DateTO WHERE transport_id=@ID", DataBase.Connection);
                Adapter.UpdateCommand.Parameters.Add(new MySqlParameter("ID", MySqlDbType.Int32, 10));
                Adapter.UpdateCommand.Parameters.Add(new MySqlParameter("TransportTypeID", MySqlDbType.Int32, 10));
                Adapter.UpdateCommand.Parameters.Add(new MySqlParameter("GovNumber", MySqlDbType.VarChar, 10));
                Adapter.UpdateCommand.Parameters.Add(new MySqlParameter("VIN", MySqlDbType.VarChar, 20));
                Adapter.UpdateCommand.Parameters.Add(new MySqlParameter("DateTO", MySqlDbType.Date));
                //INSERT
                Adapter.InsertCommand = new MySqlCommand("INSERT INTO transport (transport_type_id, gov_number, vin, date_to) VALUES (@TransportTypeID, @GovNumber, @VIN, @DateTO)", DataBase.Connection);
                Adapter.InsertCommand.Parameters.Add(new MySqlParameter("TransportTypeID", MySqlDbType.Int32, 10));
                Adapter.InsertCommand.Parameters.Add(new MySqlParameter("GovNumber", MySqlDbType.VarChar, 10));
                Adapter.InsertCommand.Parameters.Add(new MySqlParameter("VIN", MySqlDbType.VarChar, 20));
                Adapter.InsertCommand.Parameters.Add(new MySqlParameter("DateTO", MySqlDbType.Date));
                //DELETE
                Adapter.DeleteCommand = new MySqlCommand("DELETE FROM transport WHERE transport_id=@ID", DataBase.Connection);
                Adapter.InsertCommand.Parameters.Add(new MySqlParameter("ID", MySqlDbType.Int32, 10));

                //Задаём обработчики событий
                Table = new DataTable("transport");
                Table.Columns.Add(new DataColumn("transport_id", System.Type.GetType("System.Int32")));
                Table.Columns.Add(new DataColumn("transport_type_id", System.Type.GetType("System.Int32")));
                Table.Columns.Add(new DataColumn("gov_number", System.Type.GetType("System.String")));
                //Table.Columns.Add(new DataColumn("vin", System.Type.GetType("System.String")));
                Table.Columns.Add(new DataColumn("date_to", System.Type.GetType("System.DateTime")));
                Table.PrimaryKey = new DataColumn[1] {Table.Columns["transport_id"]};
                Table.TableNewRow += new DataTableNewRowEventHandler(OnNewRow);
                Table.RowChanged += new DataRowChangeEventHandler(OnRowChanged);
                Table.RowDeleted += new DataRowChangeEventHandler(OnRowDeleted);

                //Заполняем таблицу данными
                Update();

                //Создаём Binding Source для таблицы
                TableBindingSource = new BindingSource();
                TableBindingSource.DataSource = Table;

                //Настраиваем параметры автообновления
                AutoUpdater.Tick += new EventHandler(UpdateTick);
                AutoUpdater.Interval = 5000;
                AutoUpdater.Enabled = false;
            }
            /// <summary>
            /// Свойство показывает, активны ли сейчас события генерируемые при изменении таблицы транспорта
            /// </summary>
            private bool DisableActions = false;
            /// <summary>
            /// Интервал обновления данных
            /// </summary>
            public int AutoUpdateInterval
            {
                get
                {
                    return AutoUpdater.Interval;
                }
                set
                {
                    AutoUpdater.Interval = value;
                }
            }
            /// <summary>
            /// Метод автоматического обновления данных таблицы
            /// </summary>
            /// <param name="sender"></param>
            /// <param name="e"></param>
            private void UpdateTick(object sender, EventArgs e)
            {
                Update();   
            }
            /// <summary>
            /// Обновить данные таблицы
            /// </summary>
            public void Update()
            {
                DisableActions = true;
                int Pos = 0;
                if (TableBindingSource != null)
                    Pos = TableBindingSource.Position;
                Table.Clear();
                Adapter.Fill(Table);
                if (TableBindingSource != null)
                    TableBindingSource.Position = Pos;
                DisableActions = false;
            }
            #region События для обработки событий таблицы транспорта
            /// <summary>
            /// Событие генерируемое при изменение данных в строке таблицы транпорта
            /// </summary>
            /// <param name="sender"></param>
            /// <param name="e"></param>
            private void OnRowChanged(object sender, DataRowChangeEventArgs e)
            {
                if (DisableActions)
                    return;
                if (Adapter == null)
                    throw new Exception("Ошибка изменения данных таблицы транспорта.\r\nАдаптер данных не существует.");
                try
                {
                    Adapter.UpdateCommand.Parameters["ID"].Value = e.Row["transport_id"];
                    Adapter.UpdateCommand.Parameters["TransportTypeID"].Value = e.Row["transport_type_id"];
                    Adapter.UpdateCommand.Parameters["GovNumber"].Value = e.Row["gov_number"];
                    Adapter.UpdateCommand.Parameters["VIN"].Value = e.Row["vin"];
                    Adapter.UpdateCommand.Parameters["DateTO"].Value = e.Row["date_to"];
                    Adapter.UpdateCommand.ExecuteNonQuery();
                }
                catch (Exception exc)
                {
                    Documentation.ShowError(exc.Message);
                }
                //Update();
            }
            /// <summary>
            /// Событие генерируемое при создании новой записи в таблице транспорта
            /// </summary>
            /// <param name="sender"></param>
            /// <param name="e"></param>
            private void OnNewRow(object sender, DataTableNewRowEventArgs e)
            {
                if (DisableActions)
                    return;
                if (Adapter == null)
                    throw new Exception("Ошибка добавления транспорта.\r\nАдаптер данных не существует.");
                Adapter.InsertCommand.Parameters["TransportTypeID"].Value = e.Row["transport_type_id"];
                Adapter.InsertCommand.Parameters["GovNumber"].Value = e.Row["gov_number"];
                Adapter.InsertCommand.Parameters["VIN"].Value = e.Row["vin"];
                Adapter.InsertCommand.Parameters["DateTO"].Value = e.Row["date_to"];
                Adapter.InsertCommand.ExecuteNonQuery();
                //Update();
            }
            /// <summary>
            /// Событие генерируемое при удалении строки из таблицы транспорта
            /// </summary>
            /// <param name="sender"></param>
            /// <param name="e"></param>
            private void OnRowDeleted(object sender, DataRowChangeEventArgs e)
            {
                if (DisableActions)
                    return;
                if (Adapter == null)
                    throw new Exception("Ошибка удаления транспорта.\r\nАдаптер данных не существует.");
                Adapter.DeleteCommand.Parameters["ID"].Value = e.Row["transport_id"];
                Adapter.DeleteCommand.ExecuteNonQuery();
                //Update();
            }
            #endregion
        }
        /// <summary>
        /// объект предоставляющий доступ к таблице транспорта
        /// </summary>
        public AllTransport Transport = null;
        /// <summary>
        /// Класс реализующий доступ к таблице типов транспорта
        /// </summary>
        public class AllTransportTypes
        {
            private CDAOTransportions DataBase = null;
            private MySqlDataAdapter Adapter = null;
            private Timer AutoUpdater = new Timer();
            /// <summary>
            /// Таблица содержащая описание типов транспорта
            /// </summary>
            public DataTable Table = null;
            /// <summary>
            /// Коннектор данных таблицы для компонентов WinForms 
            /// </summary>
            public BindingSource TableBindingSource = null;

            public AllTransportTypes(CDAOTransportions Transportions)
            {
                if (Transportions == null)
                    throw new Exception("Ошибка загрузки справочника типов транспорта. Переданный параметр базы данных перевозок не существует.");
                if (!Transportions.IsOpen)
                    throw new Exception("Ошибка загрузки справочника типов транспорта. В переданном объекте базы даннных перевозок не установлено соединение с СУБД.");
                
                DataBase = Transportions;
                
                //Создаём и инициализиуем адаптер данных
                //SELECT
                Adapter = new MySqlDataAdapter("SELECT transport_type_id, transport_type FROM s_transport_type;", DataBase.Connection);
                //INSERT
                Adapter.InsertCommand = new MySqlCommand("INSERT INTO s_transport_type (transport_type) VALUES (@NewType);", DataBase.Connection);
                Adapter.InsertCommand.Parameters.Add("NewType", MySqlDbType.VarChar, 32, "transport_type");
                //UPDATE (CHANGE)
                Adapter.UpdateCommand = new MySqlCommand("UPDATE s_transport_type SET transport_type=@NewType WHERE transport_type_id=@ID", DataBase.Connection);
                Adapter.UpdateCommand.Parameters.Add("NewType", MySqlDbType.VarChar, 32, "transport_type");
                Adapter.UpdateCommand.Parameters.Add("ID", MySqlDbType.Int32, 10, "transport_type_id");
                //DELETE
                Adapter.DeleteCommand = new MySqlCommand("DELETE FROM s_transport_type WHERE transport_type_id=@ID", DataBase.Connection);
                Adapter.DeleteCommand.Parameters.Add("ID", MySqlDbType.Int32, 10, "transport_type_id");

                //Создаём таблицу
                Table = new DataTable("s_transport_type");
                Table.Columns.Add(new DataColumn("transport_type_id", System.Type.GetType("System.Int32")));
                Table.Columns.Add(new DataColumn("transport_type", System.Type.GetType("System.String")));

                //Устанавливаем обработчики событий
                Table.TableNewRow += new DataTableNewRowEventHandler(OnNewRow);
                Table.RowChanged += new DataRowChangeEventHandler(OnRowChanged);
                Table.RowDeleted += new DataRowChangeEventHandler(OnRowDeleted);
                
                //Заполняем таблицу данными
                Update();
                
                //Создаём коннектор к WinForms
                TableBindingSource = new BindingSource();
                TableBindingSource.DataSource = Table;
                //TableBindingSource.DataMember = "transport_type";
                //Создаём систему автообновлений

            }

            private bool DisableUpdating = false;

            public void Update()
            {
                DisableUpdating = true;
                Table.Clear();
                Adapter.Fill(Table);
                DisableUpdating = false;
            }

            #region Обработчики событий для таблицы типов транспорта

            private void OnNewRow(object sender, DataTableNewRowEventArgs e)
            {
                if (DisableUpdating)
                    return;
                Adapter.InsertCommand.Parameters["NewType"].Value = e.Row["transport_type"];
                Adapter.InsertCommand.ExecuteNonQuery();
                Update();
            }

            private void OnRowChanged(object sender, DataRowChangeEventArgs e)
            {
                if (DisableUpdating)
                    return;
                Adapter.UpdateCommand.Parameters["ID"].Value = e.Row["transport_type_id"];
                Adapter.UpdateCommand.Parameters["NewType"].Value = e.Row["transport_type"];
                Adapter.UpdateCommand.ExecuteNonQuery();
                Update();
            }

            private void OnRowDeleted(object sender, DataRowChangeEventArgs e)
            {
                if (DisableUpdating)
                    return;
                Adapter.UpdateCommand.Parameters["ID"].Value = e.Row["transport_type_id"];
                Adapter.UpdateCommand.Parameters["NewType"].Value = e.Row["transport_type"];
                Adapter.UpdateCommand.ExecuteNonQuery();
                Update();
            }

            #endregion
        }
        /// <summary>
        /// Тип экспортирующий таблицу типов транспорта
        /// </summary>
        public AllTransportTypes TransportTypes = null;
        #endregion

        #region Делегаты и события
        private void OnStateChange(Object sender, StateChangeEventArgs e)
        {
            if (StateChanged != null)
                StateChanged(e.CurrentState);
        }
        public delegate void DelegateStateChange(ConnectionState NewState);
        /// <summary>
        /// Событие происходит при изменении состояния текущего подключения.
        /// </summary>
        public event DelegateStateChange StateChanged;
        #endregion
    }
}
